<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Pluto</title><meta name="author" content="拾壹baby"><meta name="copyright" content="拾壹baby"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="个人博客">
<meta property="og:type" content="website">
<meta property="og:title" content="Pluto">
<meta property="og:url" content="http://cdn.pluto1811.com/pluto/page/2/">
<meta property="og:site_name" content="Pluto">
<meta property="og:description" content="个人博客">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png">
<meta property="article:author" content="拾壹baby">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png"><link rel="shortcut icon" href="/pluto/img/favicon.png"><link rel="canonical" href="http://cdn.pluto1811.com/pluto/page/2/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/pluto/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/pluto/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Pluto',
  isPost: false,
  isHome: true,
  isHighlightShrink: false,
  isToc: false,
  postUpdate: '2023-06-06 11:23:20'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.3.0"><link rel="alternate" href="/pluto/atom.xml" title="Pluto" type="application/atom+xml">
</head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/pluto/archives/"><div class="headline">文章</div><div class="length-num">22</div></a><a href="/pluto/tags/"><div class="headline">标签</div><div class="length-num">0</div></a><a href="/pluto/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/pluto/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="full_page" id="page-header" style="background-image: url('//cdn.pluto1811.com/cover2.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/pluto/">Pluto</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/pluto/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/pluto/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="site-info"><h1 id="site-title">Pluto</h1><div id="site-subtitle"><span id="subtitle"></span></div></div><div id="scroll-down"><i class="fas fa-angle-down scroll-down-effects"></i></div></header><main class="layout" id="content-inner"><div class="recent-posts" id="recent-posts"><div class="recent-post-item"><div class="post_cover left"><a href="/pluto/2022/09/21/scripttag/" title="在script标签写export为什么会抛错？"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1615289042307/1615289019850.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="在script标签写export为什么会抛错？"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/09/21/scripttag/" title="在script标签写export为什么会抛错？">在script标签写export为什么会抛错？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-09-21T05:20:55.000Z" title="发表于 2022-09-21 13:20:55">2022-09-21</time></span></div><div class="content">脚本和模块首先，JavaScript 有两种源文件，一种叫做脚本，一种叫做模块。这个区分是在 ES6 引入了模块机制开始的，在 ES5 和之前的版本中，就只有一种源文件类型（就只有脚本）。
脚本是可以由浏览器或者 node 环境引入执行的，而模块只能由 JavaScript 代码用 import 引入执行。
从概念上，我们可以认为脚本具有主动性的 JavaScript 代码段，是控制宿主完成一定任务的代码；而模块是被动性的 JavaScript 代码段，是等待被调用的库。
我们对标准中的语法产生式做一些对比，不难发现，实际上模块和脚本之间的区别仅仅在于是否包含 import 和 export。
脚本是一种兼容之前的版本的定义，在这个模式下，没有 import 就不需要处理加载“.js”文件问题。
现代浏览器可以支持用 script 标签引入模块或者脚本，如果要引入模块，必须给 script 标签添加 type&#x3D;“module”。如果引入脚本，则不需要 type。
&lt;script type="module" src="xxxxx.js">&lt;/script>

这样， ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/pluto/2022/09/15/css-selector/" title="除了属性和选择器，你还需要知道这些带@的规则"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1615430191758/1615430172196.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="除了属性和选择器，你还需要知道这些带@的规则"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/09/15/css-selector/" title="除了属性和选择器，你还需要知道这些带@的规则">除了属性和选择器，你还需要知道这些带@的规则</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-09-15T05:20:55.000Z" title="发表于 2022-09-15 13:20:55">2022-09-15</time></span></div><div class="content">CSS 是前端工程师几乎每天都要用的技术了，不过 CSS 的学习资料却是最糟糕的，这是因为 CSS 并没有像 HTML 和 JavaScript 那样的一份标准文档。
如果我们到 W3C 的网站上搜索看看，可以得到一些信息：
https://www.w3.org/TR/?title=css
在这里，我们一共看到了 98 份 CSS 相关的标准，它们各自从一些角度规定了 CSS 的特性。
在这样的需求下，我找到的线索就是 CSS 语法，任何 CSS 的特性都必须通过一定的语法结构表达出来，所以语法可以帮助我们发现大多数 CSS 特性。
CSS 语法的最新标准，你可以戳这里查看：
https://www.w3.org/TR/css-syntax-3/
这篇文档的阅读体验其实是非常糟糕的，它对 CSS 语法的描述使用了类似 LL 语法分析的伪代码，而且没有描述任何具体的规则。
我们拿到这份标准可以看到，去除空格、HTML 注释等无效信息，CSS 的顶层样式表由两种规则组成的规则列表构成，一种被称为 at-rule，也就是 at 规则，另一种是 qualified rule，也就是普通规则。
 ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/pluto/2022/09/09/headtag/" title="你知道head里一共能写哪几种标签吗？"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1615434517323/1615434498647.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="你知道head里一共能写哪几种标签吗？"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/09/09/headtag/" title="你知道head里一共能写哪几种标签吗？">你知道head里一共能写哪几种标签吗？</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-09-09T05:20:55.000Z" title="发表于 2022-09-09 13:20:55">2022-09-09</time></span></div><div class="content">先来了解一下什么是元信息类标签。所谓元信息，是指描述自身的信息，元信息类标签，就是 HTML 用于描述文档自身的一类标签，它们通常出现在 head 标签中，一般都不会在页面被显示出来（与此相对，其它标签，如语义类标签，描述的是业务）。
元信息多数情况下是给浏览器、搜索引擎等机器阅读的，有时候这些信息会在页面之外显示给用户，有时候则不会。
head 标签首先我们先来了解一下 head 标签，head 标签本身并不携带任何信息，它主要是作为盛放其它语义类标签的容器使用。
head 标签规定了自身必须是 html 标签中的第一个标签，它的内容必须包含一个 title，并且最多只能包含一个 base。如果文档作为 iframe，或者有其他方式指定了文档标题时，可以允许不包含 title 标签。
title 标签title 标签表示文档的标题，从字面上就非常容易理解。
你还记得吗，我们的语义类标签中也有一组表示标题的标签：h1-h6。
heading 和 title 两个英文单词意义区分十分微妙，在中文中更是找不到对应的词汇来区分。但是实际使用中，两者确实有一定区别。
在 HTML 标准中，特意 ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/pluto/2022/09/05/qiankun01/" title="qiankun源码解读-示例篇"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1615966170678/1615966002577.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="qiankun源码解读-示例篇"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/09/05/qiankun01/" title="qiankun源码解读-示例篇">qiankun源码解读-示例篇</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-09-05T05:10:55.000Z" title="发表于 2022-09-05 13:10:55">2022-09-05</time></span></div><div class="content">介绍qiankun 是基于 single-spa 做了二次封装的微前端框架，既然是二次封装，那么少不了在此基础上解决了一些 single-spa 的缺陷和不足。
single-spa 有哪些不足（其实也是qiankun的优点）1. 打包工具配置的不友好侵入型强其实说的就是第三点，更改打包工具的配置，使用 single-spa 接入微应用需要将微应用整个打包成一个 JS 文件，发布到静态资源服务器，然后在主应用中配置该 JS 文件的地址告诉 single-spa 去这个地址加载微应用。
不说其它的，就现在这个改动就存在很大的问题，将整个微应用打包成一个 JS 文件，常见的打包优化基本上都没了，比如：按需加载、首屏资源加载优化、css 独立打包等优化措施。
2. 样式隔离问题single-spa 没有做这部分的工作。这时只能通过约定命名规范来实现，比如应用样式以自己的应用名称开头，以应用名构造一个独立的命名空间，这个方式新系统还好说，如果是一个已有的系统，这个改造工作量可不小。
3. JS 隔离这部分工作 single-spa 也没有做。 JS 全局对象污染是一个很常见的现象，难以排查，有 ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/pluto/2022/09/02/qiankun02/" title="qiankun源码解读-框架源码篇"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1615971759919/1615971739665.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="qiankun源码解读-框架源码篇"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/09/02/qiankun02/" title="qiankun源码解读-框架源码篇">qiankun源码解读-框架源码篇</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-09-02T02:10:55.000Z" title="发表于 2022-09-02 10:10:55">2022-09-02</time></span></div><div class="content">框架源码整个框架的源码目录是 src，入口文件是 src&#x2F;index.ts
入口 src&#x2F;index.ts/**
 * 在示例或者官网提到的所有 API 都在这里统一导出
 */
// 最关键的三个，手动加载微应用、基于路由配置、启动 qiankun
export &#123; loadMicroApp, registerMicroApps, start &#125; from "./apis";
// 全局状态
export &#123; initGlobalState &#125; from "./globalState";
// 全局的未捕获异常处理器
export * from "./errorHandler";
// setDefaultMountApp 设置主应用启动后默认进入哪个微应用、runAfterFirstMounted 设置当第一个微应用挂载以后需要调用的一些方法
export * from "./effects";
// 类型定义
export * from "./interfaces";
// 预加载
export &#123; prefe ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/pluto/2022/08/10/babel01/" title="babel 探秘系列-基础篇"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1626858229328/1626858211842.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="babel 探秘系列-基础篇"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/08/10/babel01/" title="babel 探秘系列-基础篇">babel 探秘系列-基础篇</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-08-10T05:20:55.000Z" title="发表于 2022-08-10 13:20:55">2022-08-10</time></span></div><div class="content">babel 探秘-基础篇在现代前端开发中，babel 可以说是一道绕不过去的坎，它让我们可以尽情的使用 esnext 语法（装逼）。当然，我们可以不去关心 babel 的配置吗？毕竟有那么多，毕竟搜索引擎在手天下我有。。。能给你找一大堆理由出来，你信不信。
不过为了技术水平的提升（还嫌不够卷吗？？），还是想去了解下。
babel 是什么

Babel 是一个 Javascript 转译器 （Transpiler）
babel 最开始叫 6to5，顾名思义是 es6 转 es5，但是后来随着 es 标准的演进，有了 es7、es8 等， 6to5 的名字已经不合适了，所以改名为了 babel。
babel 是巴别塔的意思，来自圣经中的典故：当时人类联合起来兴建希望能通往天堂的高塔，为了阻止人类的计划，上帝让人类说不同的语言，使人类相互之间不能沟通，计划因此失败，人类自此各散东西。于是世上出现不同语言和种族提供解释。这座塔就是巴别塔。（取名字的艺术之高超啊。。。）


babel 有什么用

把代码中的 esnext 的新的语法、typescript 和 flow 的语法转成基于目标环境支 ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/pluto/2022/08/10/jest/" title="关于jest的TDD与BDD开发模式"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1619772970467/1619772941918.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="关于jest的TDD与BDD开发模式"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/08/10/jest/" title="关于jest的TDD与BDD开发模式">关于jest的TDD与BDD开发模式</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-08-10T05:20:55.000Z" title="发表于 2022-08-10 13:20:55">2022-08-10</time></span></div><div class="content">在 react 项目中运用 jest 自动化测试框架的探索1. 项目日益庞大后的痛点：牵一发动全身，日常开发就像是在猴子掰包谷，顾此失彼。
2. 编写的代码无理可依自己写的都不放心
。。。
因此引入自动化测试框架无疑可以给自己一剂“安心药”。
目前流行的自动化测试框架的对比


框架
优点
缺点



Mocha
主要用于单元测试
集成测试方面较弱


jest
单元、集成测试都 ok，丰富的 api
暂未发现明显缺点


本文主要介绍 jest1. 安装yarn add --dev jest 或 npm install --save-dev jest

注意：用 create-react-app myApp 或 npx create-react-app myApp 快速创建的 react 项目 自动集成 jest；
2. 如果是 react 项目建议集成 enzyme（airbnb 出品 与 react 项目配合天衣无缝）yarn add --dev enzyme enzyme-adapter-react-16

3. 项目配置可在项目根目录新建 jest.config.js
mod ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/pluto/2022/08/10/vue3-01/" title="从零实现Vue3.x-工程&amp;架构篇"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1654484986665/1654484958862.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="从零实现Vue3.x-工程&amp;架构篇"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/08/10/vue3-01/" title="从零实现Vue3.x-工程&amp;架构篇">从零实现Vue3.x-工程&amp;架构篇</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-08-10T05:20:55.000Z" title="发表于 2022-08-10 13:20:55">2022-08-10</time></span></div><div class="content">前言温故而知新，虽然 vue3.x 已经发布很久了，但对于源码的分析总能让我们每次都有收获，因此决定写一个 vue3.x 的源码分析的系列文章，vue 版本是 3.2.26。主要从以下几个方面展开分析：

工程&amp;架构
响应式系统
渲染器 &amp; diff 算法
内置组件

目录划分：
采用 monorepo 架构，做到了模块的统一管理与单独发布，相比于vue2.x尽可能的做到了模块之间的解耦.

项目的起点：package.json
npm 的钩子函数

&#123;
  "private": true,
  "version": "3.2.22",
  "scripts": &#123;
    "preinstall": "node ./scripts/preinstall.js",
  &#125;
&#125;
// 相关的钩子：依次执行
# install 之前执行这个脚本
preinstall
# 执行 install 脚本
install
# install 之后执行这个脚本
postinstall


代码风格检查与提交规范

"gitHooks": &#1 ...</div></div></div><div class="recent-post-item"><div class="post_cover left"><a href="/pluto/2022/08/06/vue3-04/" title="从零实现vue3.x-ref、computed、watch的实现"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1654586549371/1654586481783.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="从零实现vue3.x-ref、computed、watch的实现"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/08/06/vue3-04/" title="从零实现vue3.x-ref、computed、watch的实现">从零实现vue3.x-ref、computed、watch的实现</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-08-06T07:20:55.000Z" title="发表于 2022-08-06 15:20:55">2022-08-06</time></span></div><div class="content">这是从零实现 Vue3.x 系列的第四篇，上一篇我们基本实现了 Vue3 的整个响应式系统，并将部分的实现逻辑进行了封装。本章我们继续实现几个主要的 api
一、ref 的实现Proxy 只能代理对象，无法对基本类型进行属性代理，由此可见为什么我们在使用 ref 时，一定要加上.value 了吧
// ref.js
import &#123; trackEffects, triggerEffects &#125; from "./effect";
import &#123; isObject, isArray &#125; from "@mini-vue/shared";
import &#123; reactive &#125; from "./reactive";

const toReactive = (object) => (isObject(object) ? reactive(object) : object);

class RefImpl &#123;
  public __v_isRef = true;
  public deps = new Set();
  pub ...</div></div></div><div class="recent-post-item"><div class="post_cover right"><a href="/pluto/2022/08/02/vue3-03/" title="从零实现vue3.x-响应式系统"><img class="post_bg" src="http://cdn.pluto1811.com/goodsImage/1654569549756/1654569530530.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="从零实现vue3.x-响应式系统"></a></div><div class="recent-post-info"><a class="article-title" href="/pluto/2022/08/02/vue3-03/" title="从零实现vue3.x-响应式系统">从零实现vue3.x-响应式系统</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-08-02T05:20:55.000Z" title="发表于 2022-08-02 13:20:55">2022-08-02</time></span></div><div class="content">这是-从零实现 Vue3.x 系列的第三篇。
这一章节来实现 Vue3.x 的响应式系统，在此之前得先搞懂一个基础知识：Vue3.x 采用的是 es5+ 的 Proxy 的方式来生成一个代理对象，并重新定义了 getter、setter 方法，这与 Vue2.x 响应原理的区别：

初始化时 vue2.x 是利用 Object.defineProperty 来拦截对象的 getter&#x2F;setter 方法，需要遍历对象所有 key，如果对象层次较深，性能不好
通知更新过程需要维护大量 dep 实例和 watcher 实例，额外占用内存较多
无法监听到数组元素的变化，只能通过劫持重写了几个数组方法
动态新增，删除对象属性无法拦截，只能用特定 set&#x2F;delete API 代替
不支持 Map、Set 等数据结构

一、基于 new Proxy 重新定义响应方法在 packages 目录下新建 reactivity 目录
|-packages                    -- 模块集合
    |--reactivity                  --  ...</div></div></div><nav id="pagination"><div class="pagination"><a class="extend prev" rel="prev" href="/pluto/"><i class="fas fa-chevron-left fa-fw"></i></a><a class="page-number" href="/pluto/">1</a><span class="page-number current">2</span><a class="page-number" href="/pluto/page/3/#content-inner">3</a><a class="extend next" rel="next" href="/pluto/page/3/#content-inner"><i class="fas fa-chevron-right fa-fw"></i></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png" onerror="this.onerror=null;this.src='/pluto/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">拾壹baby</div><div class="author-info__description">个人博客</div></div><div class="card-info-data site-data is-center"><a href="/pluto/archives/"><div class="headline">文章</div><div class="length-num">22</div></a><a href="/pluto/tags/"><div class="headline">标签</div><div class="length-num">0</div></a><a href="/pluto/categories/"><div class="headline">分类</div><div class="length-num">0</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/xxxxxx"><i class="fab fa-github"></i><span>Follow Me</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my Blog</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/pluto/2022/10/25/me2022-10/" title="嗯，这两三年...2022年中总结"><img src="http://cdn.pluto1811.com/goodsImage/1650448154299/1650448126499.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="嗯，这两三年...2022年中总结"/></a><div class="content"><a class="title" href="/pluto/2022/10/25/me2022-10/" title="嗯，这两三年...2022年中总结">嗯，这两三年...2022年中总结</a><time datetime="2022-10-25T05:20:55.000Z" title="发表于 2022-10-25 13:20:55">2022-10-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/pluto/2022/10/25/promise/" title="Promise里的代码为什么比setTimeout先执行？"><img src="http://cdn.pluto1811.com/goodsImage/1615188358809/376997778.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="Promise里的代码为什么比setTimeout先执行？"/></a><div class="content"><a class="title" href="/pluto/2022/10/25/promise/" title="Promise里的代码为什么比setTimeout先执行？">Promise里的代码为什么比setTimeout先执行？</a><time datetime="2022-10-25T05:20:55.000Z" title="发表于 2022-10-25 13:20:55">2022-10-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/pluto/2022/10/23/jsobject/" title="JavaScript对象：啥？对象还有分类？"><img src="http://cdn.pluto1811.com/goodsImage/1615184906664/374751567.jpg" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="JavaScript对象：啥？对象还有分类？"/></a><div class="content"><a class="title" href="/pluto/2022/10/23/jsobject/" title="JavaScript对象：啥？对象还有分类？">JavaScript对象：啥？对象还有分类？</a><time datetime="2022-10-23T05:20:55.000Z" title="发表于 2022-10-23 13:20:55">2022-10-23</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/pluto/2022/10/19/hexo-ci/" title="【超实用】完美实现基于hexo的博客网站自动化部署"><img src="http://cdn.pluto1811.com/20221020140348.png" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="【超实用】完美实现基于hexo的博客网站自动化部署"/></a><div class="content"><a class="title" href="/pluto/2022/10/19/hexo-ci/" title="【超实用】完美实现基于hexo的博客网站自动化部署">【超实用】完美实现基于hexo的博客网站自动化部署</a><time datetime="2022-10-19T06:20:58.000Z" title="发表于 2022-10-19 14:20:58">2022-10-19</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/pluto/2022/10/16/jstyping/" title="JavaScript类型，有可能你不知道这些细节"><img src="http://cdn.pluto1811.com/20221020140348.png" onerror="this.onerror=null;this.src='/pluto/img/404.jpg'" alt="JavaScript类型，有可能你不知道这些细节"/></a><div class="content"><a class="title" href="/pluto/2022/10/16/jstyping/" title="JavaScript类型，有可能你不知道这些细节">JavaScript类型，有可能你不知道这些细节</a><time datetime="2022-10-16T05:20:55.000Z" title="发表于 2022-10-16 13:20:55">2022-10-16</time></div></div></div></div><div class="card-widget card-archives"><div class="item-headline"><i class="fas fa-archive"></i><span>归档</span></div><ul class="card-archive-list"><li class="card-archive-list-item"><a class="card-archive-list-link" href="/pluto/archives/2022/10/"><span class="card-archive-list-date">十月 2022</span><span class="card-archive-list-count">8</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/pluto/archives/2022/09/"><span class="card-archive-list-date">九月 2022</span><span class="card-archive-list-count">7</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/pluto/archives/2022/08/"><span class="card-archive-list-date">八月 2022</span><span class="card-archive-list-count">5</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/pluto/archives/2022/07/"><span class="card-archive-list-date">七月 2022</span><span class="card-archive-list-count">2</span></a></li></ul></div><div class="card-widget card-webinfo"><div class="item-headline"><i class="fas fa-chart-line"></i><span>网站资讯</span></div><div class="webinfo"><div class="webinfo-item"><div class="item-name">文章数目 :</div><div class="item-count">22</div></div><div class="webinfo-item"><div class="item-name">本站访客数 :</div><div class="item-count" id="busuanzi_value_site_uv"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">本站总访问量 :</div><div class="item-count" id="busuanzi_value_site_pv"><i class="fa-solid fa-spinner fa-spin"></i></div></div><div class="webinfo-item"><div class="item-name">最后更新时间 :</div><div class="item-count" id="last-push-date" data-lastPushDate="2023-06-06T03:23:20.604Z"><i class="fa-solid fa-spinner fa-spin"></i></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2023 By 拾壹baby</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/pluto/js/utils.js"></script><script src="/pluto/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><div class="js-pjax"><script>function subtitleType () {
  fetch('https://v1.hitokoto.cn')
    .then(response => response.json())
    .then(data => {
      if (true) {
        const from = '出自 ' + data.from
        const sub = []
        sub.unshift(data.hitokoto, from)
        window.typed = new Typed('#subtitle', {
          strings: sub,
          startDelay: 300,
          typeSpeed: 150,
          loop: true,
          backSpeed: 50,
        })
      } else {
        document.getElementById('subtitle').innerHTML = data.hitokoto
      }
    })
}

if (true) {
  if (typeof Typed === 'function') {
    subtitleType()
  } else {
    getScript('https://cdn.jsdelivr.net/npm/typed.js/lib/typed.min.js').then(subtitleType)
  }
} else {
  subtitleType()
}
</script></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>